#include "R_Geometry.h"
#include "Rinternals.h"
#include "R_Geometry_S4.h"
#include "WrapDefs.h"
#include "Geometry_Wrap.h"

namespace RSuperMap
{
RcppExport SEXP R_Geometry_create(SEXP geoType){
	BEGIN_RCPP
		SEXP __result;
		string strType = RTools::as_str(geoType);
		UGGeometry* pGeometry = Geometry_wrap_create(strType.c_str());

		if(pGeometry == NULL)
		{
			__result = Rcpp::wrap<bool>(false);
		}
		else
		{
			UGint nType = Name2GeometryType(strType.c_str());
			if(nType == UGGeometry::GeoPoint)
			{
				__result =  S4_GeoPoint((UGGeoPoint*)pGeometry);
			}
			else if(nType == UGGeometry::GeoLine)
			{
				__result =  S4_GeoLine((UGGeoLine*)pGeometry);
			}
			else if(nType == UGGeometry::GeoRegion)
			{
				__result =  S4_GeoRegion((UGGeoRegion*)pGeometry);
			}
			else
			{
				__result =  S4_Geometry(pGeometry);
			}
		}
		return __result;
	END_RCPP
}


RcppExport SEXP R_Geometry_getInnerPoint( SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
		UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
		
		double x = 0.0;
		double y = 0.0;
		if(Geometry_wrap_getInnerPoint(pGeometry, x, y))
		{
			std::vector<double> xysv;
			xysv.push_back(x);
			xysv.push_back(y);
			__result =  Rcpp::wrap(xysv);
		}
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}
		return __result;
	END_RCPP
}

RcppExport SEXP R_Geometry_getLength(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGdouble dLen = Geometry_wrap_getLength(pGeometry);
		__result = Rcpp::wrap(dLen);
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	return __result;
	END_RCPP
}

RcppExport SEXP R_GeoPoint_make(SEXP pointer, SEXP x, SEXP y)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeoPoint* pGeometry = (UGC::UGGeoPoint*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGdouble dx = Rcpp::as<UGdouble>(x);
		UGdouble dy = Rcpp::as<UGdouble>(y);
		GeoPoint_wrap_make(pGeometry, dx, dy);
		__result =  Rcpp::wrap<bool>(true);
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	return __result;

	END_RCPP
}

RcppExport SEXP R_Geometry_make(SEXP pointer, SEXP xs, SEXP ys, SEXP polys)
{
	BEGIN_RCPP
		SEXP __result;
		UGC::UGGeoLine* pGeometry = (UGC::UGGeoLine*) EXTPTR_PTR(pointer);
		Rcpp::NumericVector xsv(xs);
		Rcpp::NumericVector ysv(ys);

		if(xsv.size() == ysv.size())
		{
			Rcpp::IntegerVector polyCounts(polys);
			UGint nPntCount = xsv.size();
			UGint nPolyCount = (UGint)polyCounts.size();
			UGArray<UGdouble> aryX(nPntCount);
			UGArray<UGdouble> aryY(nPntCount);
			for(UGint i=0; i<nPntCount; i++)
			{
				aryX[i] = xsv[i];
				aryY[i] = ysv[i];
			}
			UGArray<UGint> aryPolyCount(nPolyCount);
			for(UGint i=0; i<nPolyCount; i++)
			{
				aryPolyCount[i] = polyCounts[i];
			}
			Geometry_wrap_make(pGeometry, aryX.GetData(), aryY.GetData(), aryPolyCount.GetData(), nPolyCount);
			__result =  Rcpp::wrap<bool>(true);
		}	
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}

		return __result;
	END_RCPP
}

RcppExport SEXP R_Geometry_getType(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
		UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
		if(pGeometry != NULL)
		{
			char* pType = Geometry_wrap_getType_name(pGeometry);
			__result = RTools::wrap_str(pType);
			wrap_delete_primitive_ary(pType);
			pType = NULL;
		}
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}
		return __result;
	END_RCPP
}

RcppExport SEXP R_Geometry_getID(SEXP pointer){
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nID = Geometry_wrap_getID(pGeometry);
		__result = Rcpp::wrap(nID);
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	return __result;
	END_RCPP
}

RcppExport SEXP R_Geometry_setID(SEXP pointer, SEXP id)
{
	BEGIN_RCPP
	SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nID = Rcpp::as<UGint>(id);
		Geometry_wrap_setID(pGeometry, nID);
		__result = id;
		return __result;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}

RcppExport SEXP R_Geometry_getPoints(SEXP pointer)
{
	BEGIN_RCPP
	SEXP __result;
	UGC::UGGeoLine* pGeometry = (UGC::UGGeoLine*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nSubCount = Geometry_wrap_getSubCount(pGeometry);
		UGint* pPolyCount = new UGint[nSubCount];
		if(Geometry_wrap_getPolyCount(pGeometry, pPolyCount))
		{
			UGint nPntCount = 0;
			for(UGint i=0; i<nSubCount; i++)
			{
				nPntCount += pPolyCount[i];
			}
			UGdouble* px = new UGdouble[nPntCount];
			UGdouble* py = new UGdouble[nPntCount];
			if(Geometry_wrap_getPoints(pGeometry, px, py))
			{
				Rcpp::NumericVector  xs(nPntCount);
				for(UGint i=0; i<nPntCount; i++)
				{
					xs[i] = px[i];
				}
				Rcpp::NumericVector  ys(nPntCount);
				for(UGint i=0; i<nPntCount; i++)
				{
					ys[i] = py[i];
				}
				Rcpp::IntegerVector  polys(nSubCount);
				for(UGint i=0; i<nSubCount; i++)
				{
					polys[i] = pPolyCount[i];
				}
				Rcpp::GenericVector points(3);
				points[0] = xs;
				points[1] = ys;
				points[2] = polys;
				__result = Rcpp::wrap(points);
			}
			else
			{
				__result = Rcpp::wrap<bool>(false);
			}

			delete[] px; 
			px = NULL;
			delete[] py;
			py = NULL;
		}
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}
		delete[] pPolyCount;
		pPolyCount = NULL;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	return __result;
	END_RCPP
}

RcppExport SEXP R_Geometry_getBounds(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
		UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
		if(pGeometry != NULL)
		{
			UGdouble rc[4];
			if(Geometry_wrap_getBounds(pGeometry, rc))
			{
				Rcpp::NumericVector xys(4);
				xys[0] = rc[0];
				xys[1] = rc[1];
				xys[2] = rc[2];
				xys[3] = rc[3];
				__result = Rcpp::wrap(xys);
				return __result;
			}
			else
			{
				__result = Rcpp::wrap<bool>(false);
			}
		}
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}
	END_RCPP
}

RcppExport SEXP R_Geometry_getArea(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGdouble dArea = Geometry_wrap_getArea(pGeometry);
		__result = Rcpp::wrap(dArea);
		return __result;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}

RcppExport SEXP R_Geometry_getDimension(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nDim = Geometry_wrap_getDimension(pGeometry);
		__result = Rcpp::wrap(nDim);
		return __result;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}

RcppExport SEXP R_GeoRegion_isHole(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeoRegion* pGeometry = (UGC::UGGeoRegion*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nSubCount = Geometry_wrap_getSubCount(pGeometry);

		UGint* pHole = new UGint[nSubCount];
		GeoRegion_wrap_holes(pGeometry, pHole);

		Rcpp::LogicalVector holes(nSubCount);
		for(UGint i=0; i<nSubCount; i++)
		{
			if(pHole[i] < 0)
			{
				holes[i] = FALSE;
			}
			else
			{
				holes[i] = TRUE;
			}	
		}
		delete[] pHole;
		pHole = NULL;
		__result = Rcpp::wrap(holes);
		return __result;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}


RcppExport SEXP R_GeoRegion_protected_decompose(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeoRegion* pGeometry = (UGC::UGGeoRegion*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		Wrap_Geometrys regions_de;
		GeoRegion_warp_protected_decompose(pGeometry, regions_de);
		if(regions_de.nCount > 0)
		{
			Rcpp::GenericVector regions(regions_de.nCount);
			for(UGint i=0; i<regions_de.nCount; i++)
			{
				UGGeoRegion* pRegion = (UGGeoRegion*)(regions_de.pGeos[i]);
				regions[i] = S4_GeoRegion(pRegion);
			}
			__result = Rcpp::wrap(regions);
			wrap_delete_primitive_ary(regions_de.pGeos);
			return __result;
		}
		else
		{
			__result = Rcpp::wrap<bool>(false);
		}
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}


RcppExport SEXP R_Geometry_sub_count(SEXP pointer)
{
	BEGIN_RCPP
		SEXP __result;
	UGC::UGGeometry* pGeometry = (UGC::UGGeometry*) EXTPTR_PTR(pointer);
	if(pGeometry != NULL)
	{
		UGint nSubCount = Geometry_wrap_getSubCount(pGeometry);
		__result = Rcpp::wrap(nSubCount);
		return __result;
	}
	else
	{
		__result = Rcpp::wrap<bool>(false);
	}
	END_RCPP
}

}